/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package estructurassa.expertos;

import estructurassa.entidades.CentroTrabajo;
import estructurassa.entidades.ClasificacionProducto;
import estructurassa.entidades.CodificacionBrisch;
import estructurassa.entidades.Maquinaria;
import estructurassa.entidades.Material;
import estructurassa.entidades.ProductoIntermedio;
import estructurassa.entidades.ProductoTerminado;
import estructurassa.entidades.Proveedor;
import estructurassa.entidades.TipoMaterial;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.hibernate.Criteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import persistencia.Fachada;
import persistencia.exceptions.ExcepcionFachada;

/**
 *
 * @author diego
 */
public class ExpertoCodigo implements Experto {

    /**
     * Los los codigos están definidos en 3 niveles. Formato de código
     * "#-##-####"
     */
    public static final int LONG_COD_SEGUNDO_NIV = 2;
    public static final int LONG_COD_TERCER_NIVEL = 4;

    /**
     * Genera el código para un material según el tipo ingresado
     *
     * @param material
     * @return
     */
    public String generarCodigo(Material material) {
        String numero = llenarCeros(material.getTipo().getUltimoMaterialIngresado() + 1, LONG_COD_TERCER_NIVEL);
        String codigoTipMat = material.getTipo().getCodigo().split("-")[1];
        String codigo = material.getTipo().getCodificacionBrisch().getCodigo() + "-" + codigoTipMat + "-" + numero;
        actualizarUltimoNumeroMaterialIngresado(material.getTipo());
        return codigo;
    }

    /**
     * Genera un codigo de Tipo de material de la forma #-##-#### a partir del
     * codigo de Brisch ingresado en el tipo y el valor del ultimo codigo
     * generado ejemplo si codigoBrisch=1 y valorCodigo=2 deve devolver
     * 1-02-0000
     *
     * @param tipo tipo de material
     * @return
     */
    public String generarCodigo(TipoMaterial tipo) {
        Criteria categoria = Fachada.getInstancia().crearCriterio(TipoMaterial.class).add(Restrictions.eq("tipo", tipo.getCodificacionBrisch()));
        categoria.addOrder(Order.asc("codigo"));
        //busca todos los tipos de materiales de esa categoria
        List tipos = Fachada.getInstancia().buscar(TipoMaterial.class, categoria);
        int nroOrden; //es el numero de categoría del nuevo tipo de material
        if (tipos.size() > 0) {//se encontraron tipos en la base de datos
            String ultimo = ((TipoMaterial) tipos.get(tipos.size() - 1)).getCodigo().split("-")[1];
            nroOrden = Integer.valueOf(ultimo) + 1;
        } else {
            nroOrden = 1;
            tipo.setUltimoMaterialIngresado(0);
        }
        String cabeceraBrisch = tipo.getCodificacionBrisch().getCodigo();
        String cabeceraTipoMat = llenarCeros(nroOrden, LONG_COD_SEGUNDO_NIV);
        String finalCadena = llenarCeros(0, LONG_COD_TERCER_NIVEL);
        return cabeceraBrisch + "-" + cabeceraTipoMat + "-" + finalCadena;
    }

    private String llenarCeros(int numero, int tamañoCadena) {

        String ultimo = String.valueOf(numero);

        while (ultimo.length() < tamañoCadena) {
            ultimo = "0" + ultimo;
        }
        return ultimo;
    }

    /**
     * Actualiza el último numero de material ingresado, según su tipo
     *
     * @param tipo
     */
    private void actualizarUltimoNumeroMaterialIngresado(TipoMaterial tipo) {
        tipo.setUltimoMaterialIngresado(tipo.getUltimoMaterialIngresado() + 1);
        try {
            Fachada.getInstancia().guardar(tipo);
        } catch (ExcepcionFachada ex) {
            Logger.getLogger(ExpertoCodigo.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * Genera el codigo para una maquinaria ingresada en un centro de trabajo
     *
     * @param maquinaria
     * @param centroTrabajo
     * @return
     */
    public String generarCodigo(Maquinaria maquinaria, CentroTrabajo centroTrabajo) {

        int nroNivel2 = Integer.valueOf(centroTrabajo.getCodigo().split("-")[2]);
        String nivel2 = llenarCeros(nroNivel2, LONG_COD_SEGUNDO_NIV);
        //busca la categoria correspondiente a la codificacion de brich
        Criteria criterioMaquinaria = Fachada.getInstancia().crearCriterio(CodificacionBrisch.class).add(Restrictions.eq("nombre", "Maquinaria"));
        String nivel1 = ((CodificacionBrisch) Fachada.getInstancia().buscar(CodificacionBrisch.class, criterioMaquinaria).get(0)).getCodigo();

        //Busca el ultima maquina ingresada
        criterioMaquinaria.add(Restrictions.eq("codigo", nivel1 + "-" + nivel2 + "%"));
        criterioMaquinaria.addOrder(Order.desc("codigo"));

        String codigoUltima = ((Maquinaria) Fachada.getInstancia().buscar(Maquinaria.class, criterioMaquinaria).get(0)).getCodigo();
        int numeroUltima = Integer.valueOf(codigoUltima.split("-")[2]);
        String nivel3 = llenarCeros(numeroUltima + 1, LONG_COD_TERCER_NIVEL);

        return nivel1 + "-" + nivel2 + "-" + nivel3;
    }

    public String generarCodigo(Maquinaria maquinaria) {
        Criteria orden = Fachada.getInstancia().crearCriterio(Maquinaria.class).addOrder(Order.desc("codigo"));
        List maquinariasEncontradas = Fachada.getInstancia().buscar(Maquinaria.class, orden);
        if (maquinariasEncontradas.isEmpty()) {
            return "6-01-0001";
        }
        String codigoUltima = ((Maquinaria) maquinariasEncontradas.get(0)).getCodigo();
        int ultimoValor = Integer.valueOf(codigoUltima.split("-")[2]);
        return codigoUltima.substring(0, 5) + llenarCeros(ultimoValor + 1, 4);
    }

    /**
     * Genera el codigo para un prodcuto terminado
     *
     * @param producto
     * @return
     */
    public String generarCodigo(ProductoTerminado producto) throws ExcepcionFachada {
        String cabecera = producto.getClasificacion().getCodigo().split("-")[0];
        String categoria = producto.getClasificacion().getCodigo().split("-")[1];
        int nuevoValor = producto.getClasificacion().getUltimoIngresado();
        nuevoValor++;
        producto.getClasificacion().setUltimoIngresado(nuevoValor);
        String valor = llenarCeros(nuevoValor, LONG_COD_TERCER_NIVEL);
        try {
            Fachada.getInstancia().guardar(producto.getClasificacion());
        } catch (ExcepcionFachada ex) {
            throw new ExcepcionFachada("ERROR al acualizar codigo Procuto");
        }

        return cabecera + "-" + categoria + "-" + valor;
    }

    public String generarCodigo(ProductoIntermedio producto) throws ExcepcionFachada {
        String cabecera = producto.getClasificacion().getCodigo().split("-")[0];
        String categoria = producto.getClasificacion().getCodigo().split("-")[1];
        int nuevoValor = producto.getClasificacion().getUltimoIngresado();
        nuevoValor++;
        producto.getClasificacion().setUltimoIngresado(nuevoValor);
        String valor = llenarCeros(nuevoValor, LONG_COD_TERCER_NIVEL);
        try {
            Fachada.getInstancia().guardar(producto.getClasificacion());
        } catch (ExcepcionFachada ex) {
            throw new ExcepcionFachada("ERROR al acualizar codigo Procuto");
        }

        return cabecera + "-" + categoria + "-" + valor;
    }

    public String generarCodigo(CentroTrabajo centro) {
        Criteria orden = Fachada.getInstancia().crearCriterio(CentroTrabajo.class).addOrder(Order.desc("codigo"));
        List centrosEncontrados = Fachada.getInstancia().buscar(CentroTrabajo.class, orden);
        if (centrosEncontrados.isEmpty()) {
            return "7-01-0001";
        }
        String codigoUltimo = ((CentroTrabajo) centrosEncontrados.get(0)).getCodigo();
        int ultimoValor = Integer.valueOf(codigoUltimo.split("-")[2]);
        return "7-01-" + llenarCeros(ultimoValor + 1, 4);
    }

    public String generarCodigo(ClasificacionProducto clasificacion) {

        Criteria criterioVigentes = Fachada.getInstancia().crearCriterio(ClasificacionProducto.class).add(Restrictions.eq("vigente", true));
        criterioVigentes.add(Restrictions.like("codigo", clasificacion.getCategoriaBrisch().getCodigo() + "-%"));
        criterioVigentes.addOrder(Order.desc("codigo"));
        List clasificacionesEncontradas = Fachada.getInstancia().buscar(ClasificacionProducto.class, criterioVigentes);

        String nroClasificacion;
        if (clasificacionesEncontradas.isEmpty()) {
            nroClasificacion = llenarCeros(1, LONG_COD_SEGUNDO_NIV);
        } else {
            ClasificacionProducto ultimaClasificacion = (ClasificacionProducto) clasificacionesEncontradas.get(0);
            int nroUltima = Integer.valueOf(ultimaClasificacion.getCodigo().split("-")[1]);
            nroClasificacion = llenarCeros(nroUltima, LONG_COD_SEGUNDO_NIV);
        }
        return clasificacion.getCategoriaBrisch().getCodigo() + "-" + nroClasificacion + "-" + llenarCeros(0, LONG_COD_TERCER_NIVEL);
    }

    public String generarCodigo(Proveedor proveedor) {
        Criteria criterioVigentes = Fachada.getInstancia().crearCriterio(Proveedor.class).add(Restrictions.eq("vigente", true));
        criterioVigentes.addOrder(Order.desc("codigo"));

        List proveedores = Fachada.getInstancia().buscar(Proveedor.class, criterioVigentes);
        if (proveedores.isEmpty()) {
            return "9-01-0000";
        }
        int ultimo = Integer.valueOf(((Proveedor) proveedores.get(0)).getCodigo().split("-")[2]);

        return "9-01-" + llenarCeros(ultimo + 1, LONG_COD_TERCER_NIVEL);
    }
}
